<?php
include_once $_SERVER['DOCUMENT_ROOT'].'/phorm/database/core/DatabaseColumn.php';
include_once $_SERVER['DOCUMENT_ROOT'].'/phorm/database/core/IDatabaseRecord.php';
include_once $_SERVER['DOCUMENT_ROOT'].'/phorm/database/core/IJoinableColumn.php';
include_once $_SERVER['DOCUMENT_ROOT'].'/phorm/database/core/IIgnorableColumn.php';
//include_once $_SERVER['DOCUMENT_ROOT'].'/phorm/core/ArrayCollection.php';

class ManyToMany extends DatabaseColumn implements IJoinableColumn, IIgnorableColumn, Iterator, Countable
{	
	// pivot_table is handled by this class' overload __get and __set methods.
	public $data_type;
	public $db_column;
	public $objects;
	
	private $query;
	private $count;
	private $currentIndex;
	
	public function __construct(IDatabaseRecord &$object, $class = null, $pivot_table = null)
	{
		// previoulsy was using debug_backtrace()
		// but we found an issue when (we think) php was running as CGI.  The ['object']
		// key was not being passed.
		// signature was:
		// public function __construct($length = null, $defaultValue = null)
		// $this->model was being set via:
		// $tmp =  debug_backtrace();
		// $this->model        = &$tmp[1]['object'];
		
		$this->model          = $object;
		$this->pivot_table    = $pivot_table;
		$this->data_type      = $class ? $class : get_class($this->model);
	}
	
	public function create()
	{
		$parent =  get_parent_class($this->model);
		$sql    = false;
		
		switch($parent)
		{
			case 'MySQLRecord':
				$sql = MySQLCRUD::createManyToMany($this);
		}
		return $sql;
		//return IDatabaseRecord::createManyToMany($this);
	}
	
	public function count()
	{
		if(!$this->count)
			$this->count = count($this->getQuery());
		
		return $this->count;
	}
	
	public function remove(IDatabaseRecord &$object)
	{
		$args = func_get_args();
		$dbh = Database::persistentConnection();
		
		foreach($args as $object)
		{
			try
			{		
				if ($object instanceof $this->data_type):
					
					$parent =  get_parent_class($this->model);	
					switch($parent)
					{
						case 'MySQLRecord':
							$query = MySQLCRUD::removeManyToMany($this, $object);
					}
					//$query = IDatabaseRecord::removeManyToMany($this, $object);
					
					$dbh->query($query);
				else:
					throw new Exception('Error:(ManyToMany) provided argument is of type ['.get_class($object).'] but a ['.$this->data_type.'] is expected');
				endif;
			}
			catch (Exception $e)
			{
				echo $e->getMessage();
				Database::finish();
				exit;
			}
		}
		
		Database::finish();
	}
	
	public function add(IDatabaseRecord &$object)
	{
		$args = func_get_args();
		$dbh = Database::persistentConnection();
		
		/*
			There appears to be a bug somewhere, either with PHP or phORM
			and it deals with dropping into nested objects within nested objects.
			The following both come back as true, even though there 
			is a value in $this->model->primary_key->value: 
			
			if (!isSet($this->model->primary_key->value))
			if (empty($this->model->primary_key->value))
			
			However, if we copy that value, eg:
			$tmpValue = $this->model->primary_key->value
			
			then
			
			if (!isSet($tmpValue))
			if (empty($tmpValue))
			
			behave as expected.
		*/
		
		$tmpValue = $this->model->primary_key->value;
		if (empty($tmpValue))
			$this->model->save();
			
		// heads up, this foreach(), overwrites the passed in argument $object
		foreach($args as $object)
		{
			try
			{		
				if ($object instanceof $this->data_type):
					/*
					 something is broken with this if statement...
					 $object->save() is not called when no PK is set
					 AV 2007-08-27
					 ---------------
					 AV 2007-10-29
					 see the note above about nested objects.
					 seems like the same thing is happening here
					 so we make a copy : $objectPrimaryKey
					*/
					$objectPrimaryKey = $object->primary_key->value;
					if (empty($objectPrimaryKey))
						$object->save();
					
					$parent =  get_parent_class($this->model);	
					switch($parent)
					{
						case 'MySQLRecord':
							$query = MySQLCRUD::addManyToMany($this, $object);
					}
					//$query = IDatabaseRecord::addManyToMany($this, $object);
					$dbh->query($query);
					
				else:
					throw new Exception('Error:(ManyToMany) provided argument is of type ['.get_class($object).'] but a ['.$this->data_type.'] is expected');
				endif;
			}
			catch (Exception $e)
			{
				echo $e->getMessage();
				Database::finish();
				exit;
			}
		}
		
		Database::finish();
	}
	
	public function getQuery()
	{
		$data_name = strtolower($this->data_type);
		$obj       = new $this->data_type();
		
		if(strtolower(get_class($this->model)) == strtolower($this->data_type))
		{
			$column1 = strtolower(get_class($this->model))."_".$this->model->primary_key->column.MySQLCRUD::SELF;
			$column2 = strtolower($this->data_type)."_".$obj->primary_key->column.MySQLCRUD::RELATIVE;
		}
		else
		{
			$column1 = strtolower(get_class($this->model))."_".$this->model->primary_key->column;
			$column2 = strtolower($this->data_type)."_".$obj->primary_key->column;
		}
		
		$q = phorm_query($this->data_type);
		$q->table($this->pivot_table);
		$q->filter('`'.$this->pivot_table.'`.'.$column1.'= "'.$this->model->primary_key->value.'"');
		$q->filter('`'.$this->pivot_table.'`.'.$column2.'= `'.$data_name.'`.'.$obj->primary_key->column);
		
		$obj->release();
		
		return $q;
	}
	
	public function one()
	{
		$q = $this->getQuery();
		$q->limit = 1;
		return $q;
	}
	
	public function all()
	{
		return $this->getQuery();
		/*$data_name = strtolower($this->data_type);
		$data      = new $this->data_type;
		$query     = "SELECT ";

		if(strtolower(get_class($this->model)) == strtolower($this->data_type))
		{
			$column1 = strtolower(get_class($this->model))."_".$this->model->primary_key->column.MySQLCRUD::SELF;
			$column2 = strtolower($this->data_type)."_".$data->primary_key->column.MySQLCRUD::RELATIVE;
		}
		else
		{
			$column1 = strtolower(get_class($this->model))."_".$this->model->primary_key->column;
			$column2 = strtolower($this->data_type)."_".$data->primary_key->column;
		}

		$results    = array();
		$collection = new ArrayCollection();

		foreach($data->columns as $key=>$value)
		{
			if(!($value instanceof IIgnorableColumn))
				$query.= '`'.$data_name."`.".$key.", ";
		}	
		// trim last comma
		$query = substr($query, 0, -2);

		$query.= " FROM `".$this->pivot_table."`, `".$data_name.'`';
		$query.= " WHERE `".$this->pivot_table."`.".$column1."= :id";
		$query.= " AND `".$this->pivot_table."`.".$column2." = `".$data_name."`.".$data->primary_key->column;
		
		echo $query;
		
		$dbh =& Database::connection();
		$stmt = $dbh->prepare($query);
		@$stmt->bindParam(':id', $this->model->primary_key->value);
		$stmt->execute();

		foreach($data->columns as $key=>$value)
		{
			if(!($value instanceof IIgnorableColumn)):
				$$key = '';
				$stmt->bindColumn($key, $$key);
			endif;
		}

		while ($row = $stmt->fetch(PDO::FETCH_BOUND)) 
		{
			$obj = new $this->data_type;
			
			foreach($obj->columns as $key=>$value)
			{
				if(!($value instanceof IIgnorableColumn))
					$value->value = $$key;
			}
			
			$obj->isNew = false;
			$collection->addItem($obj);
		}
		
		Database::finish();
		
		return $collection;
		*/
	}
	
	public function __get($property)
	{	
		if ($property == 'pivot_table')
		{
			if (empty($this->columns[$property]))
				return "pivot_".strtolower(get_class($this->model))."_".strtolower($this->data_type);
			else
				return $this->columns[$property];
		}
		else
		{
			return false;
		}
	}
	
	public function __set($property, $value)
	{
		if (!$this->columns)
			$this->columns = array();
			
		if ($property == 'pivot_table')
		{
			$this->columns[$property] = $value;
		}
	}
	
	/* ITERATOR */
	
	public function rewind() 
	{    
		if(!$this->query)
			$this->query = $this->getQuery();
			
		$this->query->rewind();
		
		$this->currentIndex = 0;
	}

	public function current() 
	{
		return $this->query->current();
	}

	public function key() 
	{
		return $this->currentIndex;
	}

	public function next() 
	{
		$this->currentIndex++;
	}

	public function valid() 
	{
		$var =  $this->currentIndex < count($this);
		return $var;
	}
	
	public function __destruct()
	{
		unset($this->query);
		parent::__destruct();
	}
}
?>
